package com.arron.juc;

/**
 * @Classname ThreadWaitAndNotifyDemo
 * @Description TODO
 * @Date 2020/8/18 23:56
 * @Created by 刘
 */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 题目：请实现 4个线程操作一个num,一个线程将num加1，一个线程将num减一，来回10个轮回
 * <p>
 * 1.判断/干活/通知
 * 2.多线程交互过程中，为了防止线程的虚假唤醒，在判断时，必须使用while循环判断，当再次被唤醒时，需要拉回来再判断一次
 */

class AirCondition {

    int num = 0;

    public synchronized void icm() throws InterruptedException {

        //判断
//        if (num != 0){
        while (num != 0) {
            this.wait();
        }
        //干活
        num++;
        System.out.println(Thread.currentThread().getName() + " 加 1 num ：" + num);
        //通知
        this.notifyAll();
    }

    public synchronized void dcm() throws InterruptedException {

        //判断 ,改为while，防止线程的虚假唤醒，当只有一个消费者和一个生产者的时候没有问题，但是如果有多个消费者，多个生产者，则会有问题
//        if (num == 0){
        while (num == 0) {
            this.wait();
        }
        //干活
        num--;
        System.out.println(Thread.currentThread().getName() + " 减 1 num ：" + num);
        //通知
        this.notifyAll();
    }


    //打印数字
    public synchronized void print0() throws InterruptedException {
//
//        while (true) {
            System.out.println(Thread.currentThread().getName() +"抢到锁：开始唤醒另一个线程");
//            Thread.sleep(1000);

            while (num < 100) {
                num++;
                System.out.println(Thread.currentThread().getName() + "打印 ：" + num);

                this.notifyAll();
                if (num == 100){
                    break;
                }
                this.wait();
            }
//            this.wait();
//        }

    }



}


class AirCondition02{


    Lock lock=new ReentrantLock();

    Condition condition1=lock.newCondition();
    Condition condition2=lock.newCondition();
    Condition condition3=lock.newCondition();

    private int num ;

    public  void print5() throws Exception {
        lock.lock();
        while (num != 0){
            condition1.await();
        }
        num++;
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"线程打印5次");
        }
        condition2.signal();
        lock.unlock();
    }
    public  void print10() throws Exception {
        lock.lock();
        while (num !=1){
            condition2.await();
        }
        num++;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"线程打印10次");
        }
        condition3.signal();
        lock.unlock();
    }
    public  void print15() throws Exception {
        lock.lock();
        while (num !=2){
            condition3.await();
        }
        num=0;
        for (int i = 0; i < 15; i++) {
            System.out.println(Thread.currentThread().getName()+"线程打印15次");
        }
        condition1.signal();
        lock.unlock();
    }




}

public class ThreadWaitAndNotifyDemo {

    public static void main(String[] args) {

        AirCondition airCondition = new AirCondition();

        AirCondition02 airCondition02 = new AirCondition02();
//        new Thread(() -> { for (int i = 0; i < 10; i++) try { airCondition.icm(); } catch (InterruptedException e) { e.printStackTrace(); } }, "A").start();
//
//        new Thread(() -> { for (int i = 0; i < 10; i++) try { airCondition.dcm(); } catch (InterruptedException e) { e.printStackTrace(); }}, "B").start();
//
//        new Thread(() -> { for (int i = 0; i < 10; i++) try { airCondition.icm(); } catch (InterruptedException e) { e.printStackTrace(); } }, "C").start();
//
//        new Thread(() -> { for (int i = 0; i < 10; i++) try { airCondition.dcm(); } catch (InterruptedException e) { e.printStackTrace(); }}, "D").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    airCondition02.print5();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();


        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    airCondition02.print10();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();


        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    airCondition02.print15();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }

}
